package net.wicp.tams.common.connector.executor.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.common.Conf;
import net.wicp.tams.common.Result;
import net.wicp.tams.common.apiext.StringUtil;
import net.wicp.tams.common.connector.ConfigInstance;
import net.wicp.tams.common.connector.beans.CusDynaBean;
import net.wicp.tams.common.connector.config.AbstractConfigClass;
import net.wicp.tams.common.connector.config.xmlParser.XMLNameSpace;
import net.wicp.tams.common.connector.executor.IBusiApp;
import net.wicp.tams.common.connector.executor.IBusiManager;
import net.wicp.tams.common.connector.executor.IConfigManager;
import net.wicp.tams.common.connector.executor.IConnInner;
import net.wicp.tams.common.connector.executor.IConnStr;
import net.wicp.tams.common.exception.ExceptAll;
import net.wicp.tams.common.exception.ProjectException;
import net.wicp.tams.common.exception.param.Request;
import net.wicp.tams.common.redis.pool.AbsPool;
import redis.clients.jedis.Jedis;

@Slf4j
public class CommonService implements IConnInner, IConnStr {
	private static Logger logger = LoggerFactory.getLogger(CommonService.class);

	private IBusiManager busiManager;

	private IConfigManager configManager;

	private AbsPool absPool;

	public final  Map<String, Integer>  needCacheMap = new HashMap<>();// 需要缓存的appkey

	

	private String[] exclude = "none".equals(Conf.get("common.connector.cache.exclude")) ? new String[0]
			: Conf.get("common.connector.cache.exclude").split(",");

	private CusDynaBean exeCommon(String appKey, CusDynaBean inputBean, IBusiApp busiApp, boolean needCheck) {
		if (busiManager == null) {
			logger.error("busiManager需要业务系统的初始化，请确认");
			CusDynaBean nullBean = ConfigInstance.getInstance().getNullOutBean(ExceptAll.project_nonull);
			return nullBean;
		}
		if (configManager == null) {
			logger.error("configManager需要业务系统的初始化，请确认");
			CusDynaBean nullBean = ConfigInstance.getInstance().getNullOutBean(ExceptAll.project_nonull);
			return nullBean;
		}
		AbstractConfigClass conf = configManager.getConfig(appKey);
		CusDynaBean clientInfo = (CusDynaBean) inputBean.get(XMLNameSpace.ControlInfo);
		if (needCheck) {// 需要检查客户端
			if (clientInfo == null) {
				return conf.newOutBean(ExceptAll.conn_nocontrol);
			}
			// TODO 客户端较验
		}
		String msgId = clientInfo.getStrValueByName(Request.msgId, String.valueOf(new Date().getTime()));// 如果没有就生成一个
		CusDynaBean outBean = conf.newOutSuc(msgId);
		if (busiApp == null) {
			try {
				busiApp = busiManager.getBean(appKey);
				if (busiApp == null) {
					CusDynaBean nullBean = ConfigInstance.getInstance().getNullOutBean(ExceptAll.conn_nobean);
					return nullBean;
				}
			} catch (Exception e) {
				String msg = "没有为[" + appKey + "]找到合适的业务bean";
				logger.error(msg, e);
				CusDynaBean nullBean = ConfigInstance.getInstance()
						.getNullOutBean(new ProjectException(ExceptAll.conn_nobean, msg));
				return nullBean;
			}
		}

		// inputBean检查
		Result paramcheck = inputBean.checkFields();
		if (!paramcheck.isSuc()) {
			outBean.setResult(paramcheck);
			return outBean;
		}
		CusDynaBean retBean;

		// 如果客户端要求用cache则直接启用,如果没有要求则看服务端相关配置,优先级：参数>needCacheSet>conf默认配置
		boolean iscache = false;
		if (clientInfo != null && StringUtil.isNotNull(clientInfo.getStrValueByName(Request.cache))) {
			iscache = Boolean.parseBoolean(clientInfo.getStrValueByName(Request.cache));
		} else if (needCacheMap.containsKey(appKey)) {
			iscache = true;
		} else {
			boolean defaultVal = Boolean.parseBoolean(Conf.get("common.connector.cache.default"));
			if ((defaultVal && !ArrayUtils.contains(exclude, appKey))
					|| (!defaultVal && ArrayUtils.contains(exclude, appKey))) {
				iscache = true;
			}
		}
		
		if (iscache && (absPool == null||!absPool.isInit())) {
			logger.error("使用缓存需要有配置redis池，请确认");
			CusDynaBean nullBean = ConfigInstance.getInstance()
					.getNullOutBean(new ProjectException(ExceptAll.param_error, appKey + "使用缓存需要有配置redis池，请确认"));
			return nullBean;
		}
		Jedis jedis = null;
		try {
			String redisKey = "";
			if (iscache) {
				// 取缓存
				jedis = absPool.getResource();
				JSONObject jsonobj = inputBean.getJsonObj();
				jsonobj.remove(Request.controlInfo);
				String key = jsonobj.toJSONString();// JSON.toJSONString(jsonobj,SerializerFeature.SortField);
				redisKey = String.format("%s:%s:%s", "api", appKey, key.replace(":", "|"));
				String redisstr = jedis.get(redisKey);
				if (StringUtil.isNotNull(redisstr)) {
					outBean.setByJson(JSON.parseObject(redisstr));
					return outBean;
				}
			}
			retBean = busiApp.exe(inputBean, outBean);
			if (iscache) {
				Object httpstatusobj = outBean.get(net.wicp.tams.common.exception.param.Response.http);
				int status = ExceptAll.getHttp(String.valueOf(httpstatusobj));
				if (status == 200) {
					jedis.set(redisKey, outBean.getJsonObj().toJSONString());
					jedis.expire(redisKey, needCacheMap.containsKey(appKey)?needCacheMap.get(appKey):Conf.getInt("common.connector.cache.expire"));// 缓存1小时
				}
			}

		} catch (ProjectException e) {
			retBean = configManager.getConfig(appKey).newOutBean(e);
			log.error("connection接口自定义的异常", e);
		} catch (Throwable e) {
			ProjectException reterror = new ProjectException(ExceptAll.project_undefined, e.getMessage());
			retBean = configManager.getConfig(appKey).newOutBean(reterror);
			log.error("connection接口未捕获的异常", e);
		} finally {
			AbsPool.returnResource(jedis);
		}
		return retBean;
	}

	@Override
	public CusDynaBean exeNoCheck(String appKey, CusDynaBean inputBean) {
		return exeCommon(appKey, inputBean, null, false);
	}

	@Override
	public CusDynaBean exe(String appKey, CusDynaBean inputBean) {
		return exeCommon(appKey, inputBean, null, true);
	}

	public CusDynaBean exe(CusDynaBean inputBean, IBusiApp busiApp) {
		CusDynaBean clientInfo = (CusDynaBean) inputBean.get(XMLNameSpace.ControlInfo);
		String appkey = clientInfo.getStrValueByName(Request.requestCommand);
		return exeCommon(appkey, inputBean, busiApp, true);
	}

	@Override
	public CusDynaBean exe(CusDynaBean inputBean) {
		return exe(inputBean, null);
	}

	/***
	 * 支持非Java的渠道接入，API由业务定义，因为它要加上注解等信息
	 * 
	 * @param appKey
	 *            appkey
	 * @param inputStr
	 *            输入参数
	 * @return 执行结果
	 */
	@Override
	public String exe(String appKey, String inputStr) {
		if (busiManager == null) {
			logger.error("busiManager需要业务系统的初始化，请确认");
			CusDynaBean nullBean = ConfigInstance.getInstance().getNullOutBean(ExceptAll.project_nonull);
			return nullBean.getJsonObj().toJSONString();
		}
		AbstractConfigClass conf = configManager.getConfig(appKey);
		CusDynaBean inputBean = conf.newInputBean();
		inputBean.setByJson(JSONObject.parseObject(inputStr));
		CusDynaBean retBean = this.exe(appKey, inputBean);
		return retBean.getJsonObj().toJSONString();
	}

	public IBusiManager getBusiManager() {
		return busiManager;
	}

	public void setBusiManager(IBusiManager busiManager) {
		this.busiManager = busiManager;
	}

	public IConfigManager getConfigManager() {
		return configManager;
	}

	public void setConfigManager(IConfigManager configManager) {
		this.configManager = configManager;
	}

	public AbsPool getAbsPool() {
		return absPool;
	}

	public void setAbsPool(AbsPool absPool) {
		this.absPool = absPool;
	}

}
